#include "stdafx.h"
#include "../lib/lib.h"
#include "url_type_cache.h"
#include <semaphore.h>

struct utc_tree
{
	struct rb_node		node;
	uint32_t			timeout;
	uint8_t				tp1;
	uint8_t				tp2;
	uint8_t				tp3;
	uint8_t				rating;
	char				url[1];
}__attribute__((aligned(sizeof(uint8_t))));

struct rb_root		utc_root =	RB_ROOT;
sem_t				utc_sem;

bool utc_lock()
{
	while(true)
	{
		if( 0 == sem_wait(&utc_sem) )
		{
			return true;
		}
		if( EINTR != errno )
		{
			return false;
		}
	}

	return false;
}

void utc_unlock(void)
{
	sem_post(&utc_sem);
}

bool utc_lock_all()
{
	int			i		= 0;

	for(i = 0; i < CHECKURL_THREAD; i++)
	{
		if( false == utc_lock() )
		{
			for(; i >= 0; i--)
			{
				sem_post(&utc_sem);
			}
			return false;
		}
	}

	return true;
}

void utc_unlock_all()
{
	int			i		= 0;

	for(i = 0; i < CHECKURL_THREAD; i++)
	{
		sem_post(&utc_sem);
	}
}
/*
 * 初始化
 */
void utc_init(void)
{
	sem_init(&utc_sem, 0, CHECKURL_THREAD);
}

struct utc_tree* _unsafe_utc_find(const char* url)
{
	struct rb_node*		node;
	struct utc_tree*	item;
	int					result;

	node = utc_root.rb_node;
	while(node)
	{
		item = rb_entry(node, struct utc_tree, node);
		result = strcmp(url, item->url);
		if(result < 0)
		{
			node = node->rb_left;
		}
		else if(result > 0)
		{
			node = node->rb_right;
		}
		else
		{
			return item;
		}
	}

	return NULL;
}
/*
 * 查询URL
 */
bool utc_query(const char* url, uint32_t* timeout, uint8_t* tp1,
		uint8_t* tp2, uint8_t* tp3, uint8_t* rating)
{
	struct utc_tree*	item;
	bool				ret			= false;

	if( false == utc_lock() )
	{
		return false;
	}
	
	item = _unsafe_utc_find(url);
	if(NULL != item)
	{
		ret = true;
		*tp1 = item->tp1;
		*tp2 = item->tp2;
		*tp3 = item->tp3;
		*rating = item->rating;
		*timeout = item->timeout;
	}

	utc_unlock();
	return ret;
}

bool _unsafe_utc_insert(struct utc_tree* item)
{
	struct rb_node		**new		= &(utc_root.rb_node);
	struct rb_node		*parent		= NULL;
	int					result		= 0;
	struct utc_tree*	this;

	while(*new)
	{
		this = rb_entry(*new, struct utc_tree, node);
		result = strcmp(item->url, this->url);
		parent = *new;
		if(result < 0)
		{
			new = &((*new)->rb_left);
		}
		else if(result > 0)
		{
			new = &((*new)->rb_right);
		}
		else
		{
			return false;
		}
	}

	rb_init_node(&(item->node));
	rb_link_node(&(item->node), parent, new);
	rb_insert_color(&(item->node), &utc_root);

	return true;
}
/*
 * 设置值
 */
void utc_set(const char* url, uint32_t timeout, uint8_t tp1, 
		uint8_t tp2, uint8_t tp3, uint8_t rating)
{
	struct utc_tree*	item;

	if( false == utc_lock_all() )
	{
		return ;
	}
	
	item = _unsafe_utc_find(url);
	if(NULL != item)
	{
		// 设置旧值
		item->timeout = timeout;
		item->tp1 = tp1;
		item->tp2 = tp2;
		item->tp3 = tp3;
		item->rating = rating;
	}
	else
	{
		// 创建新值
		item = (struct utc_tree*)malloc(sizeof(struct utc_tree) + strlen(url));
		strcpy((char*)item->url, url);
		item->tp1 = tp1;
		item->tp2 = tp2;
		item->tp3 = tp3;
		item->rating = rating;
		item->timeout = timeout;
		// 开始添加
		if(false == _unsafe_utc_insert(item))
		{
			free(item);
		}
	}

	utc_unlock_all();
}

/*
 * 删除项
 */
void utc_erase(const char* url)
{
	struct utc_tree*	item	= NULL;
	
	if(false == utc_lock_all())
	{
		return;
	}
	
	item = _unsafe_utc_find(url);
	rb_erase(&(item->node), &utc_root);
	free(item);

	utc_unlock_all();
}

void _unsafe_utc_clear(struct rb_node** node)
{
	struct utc_tree*	item;

	if(NULL == *node)
	{
		return;
	}

	_unsafe_utc_clear(&((*node)->rb_left));
	_unsafe_utc_clear(&((*node)->rb_right));

	item = rb_entry(*node, struct utc_tree, node);
	free(item);
	*node = NULL;
}
/*
 * 删除所有项
 */
void utc_clear(void)
{
	if(false == utc_lock_all())
	{
		return;
	}

	_unsafe_utc_clear( &(utc_root.rb_node) );

	utc_unlock_all();
}
